#ifndef __OS_H__
#define __OS_H__
#include <unordered_set>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "ojData.h"
#include "log.h"
#include "defer.h"
#include <vector>
using std::vector;
using std::string;

class ProcessSTD
{
public:
    std::string in, out, err;
    int inmod = O_RDONLY, outmod = O_WRONLY | O_CREAT, errmod = O_WRONLY | O_CREAT;
    ProcessSTD() : in(""),out(""),err("") {}
    ProcessSTD(const std::string& in, const std::string& out,const std::string& err) : in(in),out(out),err(err){}
};

class ProcessSTDNO
{
public:
    int in, out, err;
    ProcessSTDNO() : in(0),out(1),err(2) {}
    ProcessSTDNO(int in, int out,int err) : in(in),out(out),err(err){}
};

#ifdef __linux__
#include <linux/seccomp.h>
#include <seccomp.h>
struct seccomp_ruler {
    uint32_t action;
    int syscall;
    unsigned int arg_cnt;
    struct scmp_arg_cmp args[6];
};


template <class ...Ts>
constexpr seccomp_ruler generate_seccomp_ruler(int sys_call_id, Ts... args) {
    return seccomp_ruler{
                .action = SCMP_ACT_TRACE(sys_call_id),
                .syscall = sys_call_id,
                .arg_cnt = sizeof...(Ts),
                .args = { args... }
    };
}

extern const std::vector<seccomp_ruler> base_seccomp_rules;

inline std::vector<seccomp_ruler> operator+ (const std::vector<seccomp_ruler>& a, const std::vector<seccomp_ruler>& b) {
    std::vector<seccomp_ruler> v;
    v.insert(v.end(), a.begin(), a.end());
    v.insert(v.end(), b.begin(), b.end());
    return v;
}
#endif

#ifdef __linux__
//创建进程
pid_t createProcess_(std::string command,int max_time = -1,int max_memory = -1,
                        int enableSysCheck = 0, ProcessSTDNO pstdno = ProcessSTDNO(), 
                        const string& workPath = "", const vector<seccomp_ruler>& scmps = {});

// 重载ProcessSTD版本
pid_t createProcess_(std::string command,int max_time, int max_memory,
                        int enableSysCheck, ProcessSTD pstd, 
                        const string& workPath = "", const vector<seccomp_ruler>& scmps = {});

//监控进程
// pstdno默认为-1，-1，-1表示不捕获任何输出
ProcessStatus WatchProcess(pid_t p,int max_time,int max_memory, bool enableSysCheck, ProcessSTDNO pstdno = ProcessSTDNO(-1, -1, -1));

#elif defined(_WIN32) || defined(_WIN64)
#include <windows.h>
PROCESS_INFORMATION createProcess_(std::string command);
ProcessStatus WatchProcess(PROCESS_INFORMATION pi,int max_time,int max_memory,bool enableSysCheck);

#endif
//限制进程的cpu占用和内存占用，单位是second和byte
void setProcessReSource(int max_time = -1, int max_memory = -1);
int parseStatus(int status, int pid);

//设置定时器
// TIMER_REAL：按实际时间计时，计时到达将给进程发送SIGALRM信号。
// ITIMER_VIRTUAL：仅当进程执行时才进行计时。计时到达将发送SIGVTALRM信号给进程。
// ITIMER_PROF：当进程执行时和系统为该进程执行动作时都计时。
// 与ITIMER_VIR-TUAL是一对，该定时器经常用来统计进程在用户态和内核态花费的时间。
// 计时到达将发送SIGPROF信号给进程。
void setTimer(int max_time);

extern const char *const sysCallList[];

#ifdef __linux__

// 创建一个新的进程任务，并监听直到任务结束
// childPstd表示子进程将采用的标准流标识符
// parentPstd表示父进程，即监控进程将采用的标准流标识符，若输出流或错误流不等于-1，则将认为不是标准流，将进行对应的捕获
ProcessStatus commandExecuteResult(std::string command, int max_time, 
    int max_memory,int enableSysCheck, ProcessSTDNO childPstd, ProcessSTDNO parentPstd, 
    const string& workPath = "", const vector<seccomp_ruler>& scmps = {});

// 将ProcessSTD类型解析为ProcessSTDNO，并转发调用ProcessSTDNO版的函数
// pstd表示标准输入/输出/错误流所去向的文件，输出和错误流若为空字符串，则将由监控进程进行捕获
ProcessStatus commandExecuteResult(std::string command, int max_time, 
    int max_memory,int enableSysCheck, ProcessSTD pstd = ProcessSTD(), 
    const string& workPath = "", const vector<seccomp_ruler>& scmps = {});

// pstdno表示标准输入/输出/错误流所去向的文件描述符，输出和错误流若为-1，则将由监控进程进行捕获
ProcessStatus commandExecuteResult(std::string command, int max_time, 
    int max_memory,int enableSysCheck, ProcessSTDNO pstdno, 
    const string& workPath = "", const vector<seccomp_ruler>& scmps = {});

#endif

// 用于将标准输入输出流更换为给定的输入输出流，并返回被替代下来的标准输入输出流
inline ProcessSTDNO switchStdno(const ProcessSTDNO &pstdno);

// 将文件名打开为文件描述符
inline ProcessSTDNO stdnoFromSTD(const ProcessSTDNO &pstd);

// 关闭给定的输入输出流
inline void closeStdno(const ProcessSTDNO &pstdno);
std::string getLocalTimeStr();
void printTimeSpanToOutAndError();
void printTimeSpanToOut();
void printTimeSpanToError();
ProcessStatus reportError(int err);

#endif /* __OS_H__ */
